package myJs.user.workflow.featureSelection.uniAna

import myJs.myPkg.reactHookForm._
import myJs.tool.Tool.messages
import shared.pojo.WorkflowMission._

import scala.collection.immutable.SeqMap
import com.softwaremill.quicklens._
import myJs.Implicits._
import myJs.cps.{InputCp, RSelectMulCp, SelectCp, ToggleCp}
import myJs.tool.Tool
import myJs.user.workflow.featureSelection.FeatureSelection
import shared.pojo.MissionTool.IsPaired
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._

import scala.scalajs.js
import myJs.api.Api

import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._
import myJs.Utils._

/** Created by yz on 3/11/2020
  */
object UniAnaCp {

  case class Props(
      curI: Int,
      data: EachUniAnaData,
      dataChange: EachUniAnaData => SyncIO[Unit],
      dataModifyF: (EachUniAnaData=>EachUniAnaData) => SyncIO[Unit],
      extraData: ExtraData,
      fsData: FsData
  ){
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  val Component = ScalaFnComponent[Props] { props =>
    val (methodMap, setMethodMap) = useState(SeqMap[String, String]())
    val (showIsPaired, setShowIsPaired) = useState(false)
    val namePrefix = s"uniAna.${props.curI}"

    object FTool {

      def isPairedChange = (v: Boolean) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.isPaired).setTo(v)
          props.dataChange(newData)
        }
      }

      def methodChange = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.method).setTo(v)
          props.dataChange(newData)
        }
      }

      def fcMethodChange = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.fcMethod).setTo(v)
          props.dataChange(newData)
        }
      }

      def pValueChange = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.pValue).setTo(v)
          props.dataChange(newData)
        }
      }

      def useFdrChange = (v: Boolean) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.useFdr).setTo(v)
          props.dataChange(newData)
        }
      }

      def fdrChange = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.fdr).setTo(v)
          props.dataChange(newData)
        }
      }

      def log2FcChange = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.log2FC).setTo(v)
          props.dataChange(newData)
        }
      }

      def uniAnaGroupsModifyF = (v: List[String]) => {
        SyncIO{} >> {
          val newData = modifyLens[EachUniAnaData](_.uniAnaGroups).setTo(v)
          props.dataModifyF(newData)
        }
      }

      def dataChange = (newData: EachUniAnaData) => {
        props.dataChange(newData)
      }

    }

    val firstUpdate = useRef(true)

    useEffect(
      {
        SyncIO{} >> {
          if (props.data.uniAnaGroups.size >= 2) {
            val isMul = props.data.uniAnaGroups.size > 2
            val curMethodMap = SeqMap("auto" -> messages("wiseChoose")) ++ {
              if (isMul) {
                SeqMap("kw" -> messages("kruskalWallisTest"), "anova" -> messages("anovaTest"))
              } else {
                SeqMap("u" -> messages("uTest"), "t" -> messages("tTest"))
              }
            }
            if (curMethodMap != methodMap) {
              setMethodMap(curMethodMap)
            }else SyncIO.unit
          }else SyncIO.unit
        }
      },
      List(props.data.uniAnaGroups)
    )

    val formState = ReactHookForm.useFormState(options =
      UseFormStateOptions(
        name = namePrefix
      )
    )

    useEffect(
      SyncIO{
        Tool.refreshNodeColor(props.data.nodeId, formState, namePrefix)
      },
      List(formState)
    )

    useEffect(
      {
        IO{} >> {
          val request = IsPaired
            .Request(file = props.fsData.file, groupFile = props.fsData.groupFile, groups = props.data.uniAnaGroups)
          Api.missionTool.isPaired(request).flatMapSync { response =>
            setShowIsPaired(response)
          }
        }
      },
      List(props.data.uniAnaGroups)
    )

    val dataMatrixGroups = props.fsData.dataMatrix.groups
    useEffect(
      {
        FTool.uniAnaGroupsModifyF(dataMatrixGroups)
      },
      List(dataMatrixGroups)
    )

    val data = props.data
    val fcMethodMap = SeqMap("median" -> "Median", "mean" -> "Mean", "auto" -> messages("wiseChoose"))
    val allGroupsMap = dataMatrixGroups.optionMap
    val isMul = props.data.uniAnaGroups.size > 2

    div(
      RSelectMulCp.Props(
        value = props.data.uniAnaGroups,
        label = messages("groups"),
        name = s"${namePrefix}.uniAnaGroups",
        optionMap = allGroupsMap,
        onChange = FTool.uniAnaGroupsModifyF
      ).render,
      ToggleCp.Props(
        value = data.isPaired,
        label = messages("paired"),
        name = s"${namePrefix}.isPaired",
        valueChange = FTool.isPairedChange,
        show = showIsPaired
      ).render,
      SelectCp.Props(
        value = props.data.method,
        label = messages("analysisMethod"),
        name = s"${namePrefix}.method",
        optionMap = methodMap,
        onChange = FTool.methodChange,
        questionInfo = messages("analysisMethodInfo")
      ).render,
      SelectCp.Props(
        value = props.data.fcMethod,
        label = messages("fCCalculationMethod"),
        name = s"${namePrefix}.fcMethod",
        optionMap = fcMethodMap,
        onChange = FTool.fcMethodChange,
        questionInfo = messages("fCCalculationMethodInfo"),
        show = !isMul
      ).render,
      InputCp.Props(
        value = props.data.pValue,
        show = true,
        label = messages("pValueCutoff"),
        name = s"${namePrefix}.pValue",
        onChange = FTool.pValueChange,
        questionInfo = messages("pInfo")
      ).render,
      ToggleCp.Props(
        value = props.data.useFdr,
        label = messages("setFDRCutoff"),
        name = s"${namePrefix}.useFdr",
        valueChange = FTool.useFdrChange
      ).render,
      InputCp.Props(
        value = props.data.fdr,
        show = props.data.useFdr,
        label = messages("fDRCutoff"),
        name = s"${namePrefix}.fdr",
        onChange = FTool.fdrChange,
        questionInfo = messages("fdrInfo")
      ).render,
      InputCp.Props(
        value = props.data.log2FC,
        label = messages("log2FCCutoff"),
        name = s"${namePrefix}.log2Fc",
        onChange = FTool.log2FcChange,
        questionInfo = messages("log2FCCutoffInfo"),
        show = (!isMul)
      ).render,
      PostHocCp.Props(
        data = props.data,
        dataChange = FTool.dataChange,
        allGroups = props.data.uniAnaGroups,
        namePrefix = namePrefix
      ).render,
      TrendCp.Props(
        data = props.data,
        dataChange = FTool.dataChange,
        allGroups = props.data.uniAnaGroups,
        namePrefix = namePrefix
      ).render
    )

  }

}
